Skip to content

Merge IAM policy hierarchy#1113

Merged
david-crespo merged 19 commits into
mainfrom
merge-policy
Aug 16, 2022
Merged

Merge IAM policy hierarchy#1113
david-crespo merged 19 commits into
mainfrom
merge-policy

Conversation

@david-crespo

@david-crespo david-crespo commented Aug 11, 2022

Copy link
Copy Markdown
Collaborator

Closes #1024

2022-08-12-role-matrix

This doesn't feel good exactly but it conveys the information that's currently available and will let us get a feel for the strengths and weakness of the approach so far. I will add some notes on the experience once it's completely ready.

What's in here

  • Update to API from /policy for current silo, /global/policy for fleet omicron#1573 for /policy endpoint to get current silo policy
  • Org page displays merged silo and org policies
  • Project page displays merged silo, org, and project policies
  • Show all roles for each user
  • Only show edit or delete on rows for the immediate resource
  • Highlight "effective" role in green

Followup work

  • Copy explaining the "effective" role highlighting
  • Instead of excluding edit/delete from menu, maybe include disabled with explanatory tooltip
  • Make sure we can handle silo groups too
  • "Add user to org/project" language on button is very misleading because a user can be added even if they already have access through the parent org or silo. It's more like "give user a role specifically on this project".
  • The matrix requires referring to the silo role, but we probably shouldn't say "silo"!

@vercel

vercel Bot commented Aug 11, 2022

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Updated
console-ui-storybook ✅ Ready (Inspect) Visit Preview Aug 16, 2022 at 3:01PM (UTC)

@david-crespo david-crespo marked this pull request as ready for review August 12, 2022 21:39
return (
<Badge color={effectiveRole === cellRole ? 'default' : 'neutral'}>{cellRole}</Badge>
)
}

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is all kind of ridiculous, but it lets us do the latter instead of something like the the former:

-cell: (info) => <RoleBadge effectiveRole={info.row.original.effectiveRole} role={info.getValue()} />
+cell: RoleBadge

Comment thread app/pages/OrgAccessPage.tsx Outdated
(row) => row.id
),
[siloRows, orgRows]
)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this logic is almost identical between org and project — however the shared row processing logic I had before was kind of terrible, so I can't bring myself to extract this.

cell: (info) => <Badge color="neutral">{info.getValue()}</Badge>,
colHelper.accessor('siloRole', {
header: 'Silo role',
cell: RoleBadgeCell,

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in addition to being very clean, this actually enforces that the row type has effectiveRole on it, which is pretty cool

name: string
siloRole: SiloRole | undefined
orgRole: OrganizationRole | undefined
projectRole: ProjectRole | undefined

@david-crespo david-crespo Aug 12, 2022

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Strictly speaking there should always be at least one of the three roles. I considered using type-fest's RequireAtLeastOne to represent that, but meh. The reason not to is there's nothing in the code that depends on it, because the cells are only looking at their own value, not the whole set.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's fine. In the case where at least one role is provided that sounds like an error case we'd need to handle at runtime anyway.

Comment on lines +13 to +24
await expectRowVisible(table, {
ID: 'user-1',
Name: 'Hannah Arendt',
'Silo role': 'admin',
'Org role': '',
})
await expectRowVisible(table, {
ID: 'user-2',
Name: 'Hans Jonas',
'Silo role': '',
'Org role': 'viewer',
})

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These really are so much better, ha

Comment thread app/components/RoleBadgeCell.tsx Outdated
import type { OrganizationRole, ProjectRole, SiloRole } from '@oxide/api'
import { Badge } from '@oxide/ui'

// I think there are changes in RT 8.4+ that make this less ridiculous

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was right

Comment thread libs/api/roles.ts
export const getOrgRole = getMainRole(orgRoleOrder)
export const getEffectiveOrgRole = (
roles: OrganizationRole[]
): OrganizationRole | undefined => sortBy(roles, (role) => orgRoleOrder[role])[0]

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the changes from here up are just cleanup and renaming. I didn't like this stuff, now I feel slightly better about it

Comment thread libs/api/roles.ts
// wouldn't be a group
roleName: getMainRole(roleOrder)(groupRoleAssignments.map((ra) => ra.roleName))!,
}))
}, [policy, usersDict, roleOrder])

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The main change is that we are no longer doing a groupBy here — we're doing it in the calling code instead, in the project and org access pages. useUserRows is much easier to understand now: it takes a list of role assignments and adds some info to each one with a simple map.

@just-be-dev

Copy link
Copy Markdown
Contributor

Are there any other changes pending before this PR can be merged? I know there was some discussion around design improvements, but I wasn't sure if that was in scope with this PR.

@david-crespo

david-crespo commented Aug 16, 2022

Copy link
Copy Markdown
Collaborator Author

Nope, this is complete. I will follow up with a look at groups, but I don’t think there is currently a way to fetch a group or a list of groups from the API, so that work will probably have to wait a week or two.

if (!cellRole) return null
const effectiveRole = info.row.original.effectiveRole
return (
<Badge color={effectiveRole === cellRole ? 'default' : 'neutral'}>{cellRole}</Badge>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Visually secondary might be a better fit here. It definitely can wait until a design pass though.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might not be the right place for it, but having tooltips on the non-effective roles would be good.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, definitely. Eugene and Ben are thinking about all that.

Comment on lines +46 to 47
apiQueryClient.prefetchQuery('policyView', {}),
apiQueryClient.prefetchQuery('organizationPolicyView', requireOrgParams(params)),

@just-be-dev just-be-dev Aug 16, 2022

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When you demo this, it'd be good to call out that pagination would be a challenge. As I'm thinking about this, it almost seems like these endpoints should more be policyList and organizationPolicyList with /policy/<user-id> being a valid lookup. If we did that then we could just use policy list and do a lookup (or future batch lookup) for the related endpoints. Or it's just PolicyView with a filter? Either way..

Again, nothing to do in this PR.

Comment thread app/pages/OrgAccessPage.tsx Outdated
const orgRows = useUserRows(orgPolicy?.roleAssignments, 'org')
const siloRows = useUserRows(siloPolicy?.roleAssignments, 'silo')
const rows = useMemo(() => {
const users = groupBy(siloRows.concat(orgRows), (u) => u.id).map(([id, ras]) => {

@just-be-dev just-be-dev Aug 16, 2022

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is ras short for? Role assignments?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah. it sucks, I'll fix it and then merge

@just-be-dev just-be-dev left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whew, tough little piece of work. Good job though, I think this'll really be helpful in visualizing some of the challenges around our IAM model.

Good to merge when you're ready 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Aggregate policy by pulling it for parent resources and merging

2 participants